package userPages;
import pages.*;

import java.io.IOException;
import java.security.MessageDigest;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import database.DBException;
import database.DBUtils;

import templates.Template;

/**
 * Servlet implementation class UserInfo
 */
public class UserInfo extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private static final String templateName = "user_templates\\user_info";
	private static final String pageTitle = "User Info";
	
	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public UserInfo() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String criticalError = "";
		try {
			String showUserLogin = LMUtils.getUserLogin(request);
			// String showUserLogin = LMUtils.getUserLogin(request);
			Template template = userInfoTemplate(showUserLogin,
					getServletContext());

			template.addChange("errorDetails", LMUtils.getRequestAttribute(
					request, "errorDetails"));
			template.addChange("errorPassword", LMUtils.getRequestAttribute(
					request, "errorPassword"));

			template.addChange("old_passwordError", LMUtils
					.getRequestAttribute(request, "oldPasswordError"));
			template.addChange("new_passwordError", LMUtils
					.getRequestAttribute(request, "newPasswordError"));
			template.addChange("c_passwordError", LMUtils.getRequestAttribute(
					request, "NewCPasswordError"));
			response.getWriter().print(
					template.createPage(pageTitle, showUserLogin));
		} catch (Exception e) {
			criticalError = e.getMessage();
		}

		if (!criticalError.isEmpty()) {
			try {
				response.getWriter().print(
						ErrorPage.generateErrorPage(criticalError, LMUtils
								.getUserLogin(request)));
			} catch (InternalErrorException e1) {
				response.getWriter().print(criticalError);
			}
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		LMUtils.setRequestAttribute(request, "errorDetails", "");
		LMUtils.setRequestAttribute(request, "errorPassword", "");
		LMUtils.setRequestAttribute(request, "oldPasswordError", "");
		LMUtils.setRequestAttribute(request, "newPasswordError", "");
		LMUtils.setRequestAttribute(request, "NewCPasswordError", "");
		String action = request.getParameter("editInfo");
		String OldPassword = "", NewPassword = "", NewCPassword = "";
		response.setHeader("Cache-Control",
				"no-store, no-cache, must-revalidate");

		try {
			if (action != null) {
				if (LMUtils.getRequestParameterValueNotEmpty(request,
						"editInfo") != null) {
					// edit Info

					String userLogin = LMUtils.getUserLogin(request);

					// getting all the fields
					try {
						String newUserName = LMUtils
								.getRequestParameterValueNotEmpty(request,
										"name");
						String newPhone = LMUtils.getRequestParameterValue(
								request, "phone");
						String newAddress = LMUtils.getRequestParameterValue(
								request, "address");
						changeUserInfo(userLogin, newUserName, newPhone,
								newAddress);
					} catch (MissingParameterException e) {
						LMUtils.setRequestAttribute(request, "errorDetails",
								"Please fill in all fields");
					}
				}
			} else {
				try {
					OldPassword = LMUtils.getRequestParameterValueNotEmpty(
							request, "old_password");
				} catch (MissingParameterException e) {
					LMUtils.setRequestAttribute(request, "errorPassword",
							"Please fill in all fields");
					LMUtils.setRequestAttribute(request, "oldPasswordError",
							"This field is required");
				}
				try {
					NewPassword = LMUtils.getRequestParameterValueNotEmpty(
							request, "new_password");
				} catch (MissingParameterException e) {
					LMUtils.setRequestAttribute(request, "errorPassword",
							"Please fill in all fields");
					LMUtils.setRequestAttribute(request, "newPasswordError",
							"This field is required");
				}
				try {
					NewCPassword = LMUtils.getRequestParameterValueNotEmpty(
							request, "c_password");
				} catch (MissingParameterException e) {
					LMUtils.setRequestAttribute(request, "errorPassword",
							"Please fill in all fields");
					LMUtils.setRequestAttribute(request, "NewCPasswordError",
							"This field is required");
				}
				if (LMUtils.getRequestAttribute(request, "errorPassword")
						.isEmpty()) {
					
					LMUtils.setRequestAttribute(request, "errorPassword",
							changeUserPassword(LMUtils.getUserLogin(request),
									OldPassword, NewPassword, NewCPassword));
					// errorPassword = "Done!";
				}
			}
		} catch (Exception e) {
			// no edit info was asked
		}
		doGet(request, response);
	}

	public static Template userInfoTemplate(String userLogin,
			ServletContext servletContext) throws DBException {
		Connection conn = null;
		PreparedStatement selectUserStmt = null;
		ResultSet rs = null;
		try {
			String usersTableName = LMUtils.getContextParameterValue(
					servletContext, "db.UsersTableName");

			conn = DBUtils.getConnection();
			selectUserStmt = conn
					.prepareStatement("SELECT `Name`, `Phone`, `Address` FROM `"
							+ usersTableName + "` WHERE `Login` = ?;");
			selectUserStmt.setString(1, userLogin);
			rs = selectUserStmt.executeQuery();
			if (rs == null || !rs.next()) {
				throw new DBException("User not found");
			} else {
				Template template = new Template(templateName);
				template.addChange("showUserID", userLogin);
				template.addChange("name", rs.getString("Name"));
				template.addChange("phone", rs.getString("Phone"));
				template.addChange("address", rs.getString("Address"));

				return template;
			}
		} catch (Exception e) {
			throw new DBException(e.getMessage(), e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(selectUserStmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Changes user's info. Caution! There is no check if the user can perform
	 * the action. Check it before calling this method
	 * 
	 * @param initiatorLogin
	 * @param toUserLogin
	 * @param newUserInfo
	 * @throws DBException
	 */
	public static void changeUserInfo(String userLogin, String newUserName,
			String newPhone, String newAddress) throws DBException {
		Connection conn = null;
		PreparedStatement updateUserStmt = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConnection();
			updateUserStmt = conn
					.prepareStatement("UPDATE `Users` SET `Name` = ?, `Phone` = ?, `Address` = ? WHERE `Login` = ? ;");
			updateUserStmt.setString(1, newUserName);
			updateUserStmt.setString(2, newPhone);
			updateUserStmt.setString(3, newAddress);
			updateUserStmt.setString(4, userLogin);
			updateUserStmt.execute();

		} catch (Exception e) {
			throw new DBException("Update failed: " + e.getMessage(), e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(updateUserStmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Change user password
	 * @param username
	 * @param OldPassword
	 * @param NewPasswordNew
	 * @param NewCPassword
	 * @return
	 */
	private String changeUserPassword(String username, String OldPassword,
			String NewPasswordNew, String NewCPassword) {
		Connection conn = null;
		PreparedStatement updateUserStmt = null;
		ResultSet rs = null;
		PreparedStatement stmt = null;

		if (NewPasswordNew.compareTo(NewCPassword) != 0) {
			return "Please, enter new password correctly!";

		}
		try {
			conn = DBUtils.getConnection();
			String query = "SELECT Password from Users WHERE Login='"
					+ username + "';";
			stmt = conn.prepareStatement(query);
			//System.out.println(query);
			rs = stmt.executeQuery();
			//System.out.println("Query Down");
			if (rs.next()) {
				String old = rs.getString("Password");

				MessageDigest digest = java.security.MessageDigest
						.getInstance("MD5");
				digest.update(OldPassword.getBytes("iso-8859-1"), 0,
						OldPassword.length());
				OldPassword = new String(convertToHex(digest.digest()));

				if (OldPassword.compareTo(old) == 0) {
					digest.update(NewPasswordNew.getBytes("iso-8859-1"), 0,
							NewPasswordNew.length());
					NewPasswordNew = new String(convertToHex(digest.digest()));
					updateUserStmt = conn
							.prepareStatement("UPDATE `Users` SET `Password` = ? WHERE `Login` = ? ;");
					updateUserStmt.setString(1, NewPasswordNew);
					updateUserStmt.setString(2, username);
					updateUserStmt.execute();

				} else {
					return "Your Old password is wrong!";
				}
			}
		} catch (Exception e) {
			return "Update failed: " + e.getMessage();
		} finally {
			DBUtils.close(rs);
			DBUtils.close(updateUserStmt);
			DBUtils.close(conn);
		}
		return "Done!";

	}

	private static String convertToHex(byte[] data) {
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < data.length; i++) {
			int halfbyte = (data[i] >>> 4) & 0x0F;
			int two_halfs = 0;
			do {
				if ((0 <= halfbyte) && (halfbyte <= 9))
					buf.append((char) ('0' + halfbyte));
				else
					buf.append((char) ('a' + (halfbyte - 10)));
				halfbyte = data[i] & 0x0F;
			} while (two_halfs++ < 1);
		}
		return buf.toString();
	}

}
